package com.ocom.exposeapi.controller;

import com.alibaba.fastjson.JSON;
import com.ocom.common.constant.ExposeApiUrl;
import com.ocom.common.dto.CompanyDockListDto;
import com.ocom.common.dto.DockKeyDto;
import com.ocom.common.dto.TimerPaymentCallBackDto;
import com.ocom.common.entity.card.EntityXfAccountInfo;
import com.ocom.common.entity.company.EntityComDockApi;
import com.ocom.common.entity.company.EntityDockKey;
import com.ocom.common.entity.human.EntityPersonnelInfo;
import com.ocom.common.enums.ResultEnum;
import com.ocom.common.request.company.GetDockApiUrlRequest;
import com.ocom.common.request.company.GetReplyApiParaRequest;
import com.ocom.common.request.payhandle.ZkzlPayRequest;
import com.ocom.common.resp.Result;
import com.ocom.common.utils.ResultUtil;
import com.ocom.common.utils.SpringUtils;
import com.ocom.common.utils.abc.HttpClientUtils;
import com.ocom.common.utils.abc.dto.ABCReturnDto;
import com.ocom.common.utils.zkzl.SecretRule;
import com.ocom.common.utils.zkzl.SecretUtil;
import com.ocom.common.utils.zkzl.dto.*;
import com.ocom.common.vo.company.CompanyDockListVo;
import com.ocom.common.vo.company.DockApiUrlVo;
import com.ocom.common.vo.human.UserInfoVo;
import com.ocom.exposeapi.feign.CompanyClientService;
import com.ocom.exposeapi.feign.HumanFeignService;
import com.ocom.exposeapi.feign.PayConfigClientService;
import com.ocom.exposeapi.feign.PayHandleClientService;
import com.ocom.exposeapi.vo.zkzl.ZkzlAuthTokenRequest;
import com.ocom.exposeapi.vo.zkzl.ZkzlAuthTokenResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@Slf4j
@RestController
public class ZkzlController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private CompanyClientService companyClientService;
    @Autowired
    private HumanFeignService humanFeignService;
    @Autowired
    private PayConfigClientService payConfigClientService;
    @Autowired
    private PayHandleClientService payHandleClientService;

    static final String DOCK_CODE = "zkzl";
    static final String SERVER_CODE = "zkzl#ocom";
    static final String TOKEN_DOCK_API_CODE = "zkzl#authToken";
    static final String SID = "170000000000051001";//dockServer中获取？

    @GetMapping(ExposeApiUrl.URL_ExposeApi_ZkzlGetUser)
    public GetUserResponse getUser(HttpServletRequest request, HttpServletResponse httpResponse) throws Exception {
        logger.info("进入getUser接口---------------");

        GetUserResponse returnResponse = new GetUserResponse();
        ZKZLReturnDto returnDto = new ZKZLReturnDto();

        try {
            Map<String, String> requestParamMap = getParam(request, returnDto);
            logger.info("----------------------requestParamMap参数" + requestParamMap.toString());

            EntityDockKey entityDockKey = getDockKey(DOCK_CODE, returnDto);

            String requestContent = verificationAndDecryption(requestParamMap, entityDockKey, returnDto);
            GetUserRequest getRequest = JSON.parseObject(requestContent, GetUserRequest.class);


            Map<String, String> idMap = getPidAndComId(getRequest.getUid(), returnDto);
            Integer pId = Integer.valueOf(idMap.get("pId"));
            Long comId = Long.valueOf(idMap.get("comId"));

            getComDockList(comId, DOCK_CODE, SERVER_CODE, getRequest.getChannel(), returnDto);

            personnelGetPersonInfoAndSetUser(comId, pId, returnDto);

            getXFAccount(comId, pId, returnDto);


        } catch (Exception e) {
            e.printStackTrace();
            logger.info("----------------------getUser接口异常：" + returnDto.getReturnMessage());

        } finally {
            returnResponse.setCode(returnDto.getReturnCode());
            returnResponse.setSerial(String.valueOf(new Date().getTime()));
            returnResponse.setMessage(returnDto.getReturnMessage());
            GetUserResponse.DataRecord dataRecord = returnResponse.buildData();
            dataRecord.setUserName(returnDto.getUserName());
            dataRecord.setUserAccount(returnDto.getUserAccount());
            dataRecord.setUserStatus(returnDto.getUserStatus());
            returnResponse.setData(dataRecord);
        }
        logger.info("----------------------getUser接口响应：" + returnResponse);

        return returnResponse;
    }


    @GetMapping(ExposeApiUrl.URL_ExposeApi_ZkzlGetWallet)
    public GetWalletResponse getWallet(HttpServletRequest request, HttpServletResponse httpResponse) throws IOException {
        logger.info("进入getWallet接口---------------");

        GetWalletResponse returnResponse = new GetWalletResponse();
        ZKZLReturnDto returnDto = new ZKZLReturnDto();

        try {
            Map<String, String> requestParamMap = getParam(request, returnDto);
            logger.info("----------------------requestParamMap参数" + requestParamMap.toString());

            EntityDockKey entityDockKey = getDockKey(DOCK_CODE, returnDto);
            String requestContent = verificationAndDecryption(requestParamMap, entityDockKey, returnDto);

            GetWalletRequest getRequest = JSON.parseObject(requestContent, GetWalletRequest.class);

            Map<String, String> idMap = getPidAndComId(getRequest.getUid(), returnDto);
            Integer pId = Integer.valueOf(idMap.get("pId"));
            Long comId = Long.valueOf(idMap.get("comId"));

            EntityXfAccountInfo entityXfAccountInfo = getXFAccount(comId, pId, returnDto);
            returnDto.setBalance(entityXfAccountInfo.getAccountRechargeMoney().intValue() + entityXfAccountInfo.getAccountSubsidyMoney().intValue());

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("----------------------getWallet接口异常：" + returnDto.getReturnMessage());
        } finally {
            returnResponse.setCode(returnDto.getReturnCode());
            returnResponse.setSerial(String.valueOf(new Date().getTime()));
            returnResponse.setMessage(returnDto.getReturnMessage());

            GetWalletResponse.DataRecord dataRecord = returnResponse.buildData();
            dataRecord.setBalance(returnDto.getBalance());
            returnResponse.setData(dataRecord);
        }

        logger.info("----------------------getWallet接口响应：" + returnResponse);
        return returnResponse;
    }

    @GetMapping(ExposeApiUrl.URL_ExposeApi_ZkzlPushPosData)
    public PushPostDataResponse pushPosData(HttpServletRequest request, HttpServletResponse httpResponse) throws IOException {
        logger.info("进入pushPosData接口---------------");

        PushPostDataResponse returnResponse = new PushPostDataResponse();
        ZKZLReturnDto returnDto = new ZKZLReturnDto();

        try {
            Map<String, String> requestParamMap = getParam(request, returnDto);
            logger.info("----------------------requestParamMap参数" + requestParamMap.toString());

            EntityDockKey entityDockKey = getDockKey(DOCK_CODE, returnDto);
            String requestContent = verificationAndDecryption(requestParamMap, entityDockKey, returnDto);

            PushPostDataRequest getRequest = JSON.parseObject(requestContent, PushPostDataRequest.class);
            Map<String, String> idMap = getPidAndComId(getRequest.getUid(), returnDto);
            Integer pId = Integer.valueOf(idMap.get("pId"));
            Long comId = Long.valueOf(idMap.get("comId"));

            ZkzlPayRequest zkzlPayRequest = new ZkzlPayRequest();
            zkzlPayRequest.setCompanyId(comId);
            zkzlPayRequest.setUserId(pId.longValue());
            zkzlPayRequest.setTradeNo("ZK" + getRequest.getOrderNumber());
            zkzlPayRequest.setAmount(getRequest.getPosMoney());
            zkzlPayRequest.setDescribe(getRequest.getDescribe());
            zkzlPayRequest.setPosAddress(getRequest.getPosAddress());
            zkzlPayRequest.setMachineId(getRequest.getMachineId());
            zkzlPayRequest.setTradeTime(getRequest.getOpenTime());
            zkzlPayRequest.setConsType(getRequest.getPosType() + 200);

            Result zkzlResult =  payHandleClientService.zkzlPay(zkzlPayRequest);
            if (zkzlResult == null || 200 != zkzlResult.getCode()) {
                returnDto.setReturnCode(999);
                returnDto.setHandleStatus(2);
                returnDto.setReturnMessage(zkzlResult.getMsg());
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("----------------------pushPosData接口异常：" + returnDto.getReturnMessage());

            returnDto.setReturnCode(999);
            returnDto.setHandleStatus(2);
            returnDto.setReturnMessage("系统异常");
        } finally {
            returnResponse.setCode(returnDto.getReturnCode());
            returnResponse.setSerial(String.valueOf(new Date().getTime()));
            returnResponse.setMessage(returnDto.getReturnMessage());

            PushPostDataResponse.DataRecord dataRecord = returnResponse.buildData();
            dataRecord.setHandleStatus(returnDto.getHandleStatus());
            returnResponse.setData(dataRecord);
        }
        logger.info("----------------------pushPosData接口响应：" + returnResponse);

        return returnResponse;
    }

    @PostMapping(ExposeApiUrl.URL_ExposeApi_ZkzlAuthToken)
    public Result authToken(@RequestBody Map<String, Object> map) throws IOException {
        logger.info("进入authToken接口---------------");
        if (map.get("comId") ==null || map.get("userName")==null || map.get("password")==null){
            return ResultUtil.error(ResultEnum.Err_203);
        }

        ZKZLReturnDto returnDto = new ZKZLReturnDto();
        try {

            EntityDockKey entityDockKey = getDockKey(DOCK_CODE, returnDto);

            GetDockApiUrlRequest getDockApiUrlRequest = new GetDockApiUrlRequest();
            getDockApiUrlRequest.setComId(entityDockKey.getComId());
            getDockApiUrlRequest.setDockCode(DOCK_CODE);
            getDockApiUrlRequest.setGrade(0);
            Result getDockApiUrlResult = companyClientService.getDockApiUrl(getDockApiUrlRequest);

            if (null == getDockApiUrlResult || null == getDockApiUrlResult.getData()) {
                returnDto.setReturnCode(206);
                returnDto.setReturnMessage("读取通讯接口URL失败");
                throw new Exception(returnDto.getReturnMessage());
            }
            List<DockApiUrlVo> getDockApiUrlList = JSON.parseArray(JSON.toJSONString(getDockApiUrlResult.getData()), DockApiUrlVo.class);
            Optional<DockApiUrlVo> dockApiUrl = getDockApiUrlList.stream().filter(o -> o.getDockApiCode().equals(TOKEN_DOCK_API_CODE)).findFirst();
            if (dockApiUrl.isPresent()){
                String reqUrl = dockApiUrl.get().getRequestUrl();

                ZkzlAuthTokenRequest zkzlAuthTokenRequest = new ZkzlAuthTokenRequest();
                zkzlAuthTokenRequest.setUserName(map.get("userName").toString());
                zkzlAuthTokenRequest.setUserPassword(map.get("password").toString());
                String requestParam = JSON.toJSONString(zkzlAuthTokenRequest);

                SecretRule secretRule = new SecretRule().setSid(SID).setAes(entityDockKey.getAesKey()).setMd5(entityDockKey.getMd5Key());
                String aesData = SecretUtil.encryptByAES(secretRule, requestParam);
                String md5Data = SecretUtil.encryptByMD5(secretRule, aesData);
                logger.info("加密前参数data:" + requestParam);
                logger.info("X-Sign:" + md5Data + ",参数data:" + aesData);

                //发送签名信息获取返回签名信息
                reqUrl += "?data=" + aesData;
                Map responseMap = SecretUtil.doGet(reqUrl, SID, md5Data);
                logger.info("接收到的报文：" + responseMap);
                int code = Double.valueOf(responseMap.get("Code").toString()).intValue();
                if (200 == code) {
                    Map dataMap = (Map) responseMap.get("Data");
                    returnDto.setReturnCode(code);
                    returnDto.setToken(dataMap.get("Token").toString());
                } else {
                    returnDto.setReturnCode(code);
                    returnDto.setReturnMessage("读取通讯接口URL失败");
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("----------------------authToken接口异常：" + returnDto.getReturnMessage());

            returnDto.setReturnCode(206);
        }
        logger.info("----------------------authToken接口响应：" + returnDto.getToken());

        return returnDto.getReturnCode() != 200 ? ResultUtil.error(ResultEnum.Err_4114) : ResultUtil.success(returnDto.getToken());
    }

    @PostMapping(ExposeApiUrl.URL_ExposeApi_zkzlTimerPaymentCallBack)
    public void zkzlTimerPaymentCallBack(@RequestBody TimerPaymentCallBackDto dto) {
        payHandleClientService.zkzlTimerPaymentCallBack(dto);
    }


    private EntityDockKey getDockKey(String dockCode, ZKZLReturnDto returnDto) throws Exception {
        DockKeyDto dockKeyDto = new DockKeyDto();
        dockKeyDto.setDockCode(dockCode);
        dockKeyDto.setGrade(20);
        Result dockKeyResult = companyClientService.getDockKey(dockKeyDto);
        if (dockKeyResult == null || 200 != dockKeyResult.getCode()) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("密钥不存在");
            throw new Exception(returnDto.getReturnMessage());
        }
        EntityDockKey entityDockKey = JSON.parseObject(JSON.toJSONString(dockKeyResult.getData()), EntityDockKey.class);
        if (null == entityDockKey  || StringUtils.isBlank(entityDockKey.getMd5Key()) || StringUtils.isBlank(entityDockKey.getAesKey())) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("密钥不存在");
            throw new Exception(returnDto.getReturnMessage());
        }
        return entityDockKey;
    }

    private String verificationAndDecryption(Map<String, String> map, EntityDockKey entityDockKey, ZKZLReturnDto returnDto) throws Exception {
        String requestContent = map.get("requestContent");
        String xsid = map.get("xsid");
        String xsign = map.get("xsign");

        SecretRule secretRule = new SecretRule().setSid(xsid).setAes(entityDockKey.getAesKey()).setMd5(entityDockKey.getMd5Key());
        String sign = SecretUtil.encryptByMD5(secretRule, requestContent).toLowerCase();
        logger.info("本地签名：{}", sign);

        if (!sign.equals(xsign)) {
            logger.info("验签失败{},{}", sign, xsign);
            returnDto.setReturnCode(204);
            returnDto.setReturnMessage("验签失败");
            throw new Exception(returnDto.getReturnMessage());
        }

        requestContent = SecretUtil.decryptByAES(secretRule, requestContent);
        logger.info("解密后的报文：{}", requestContent);

        return requestContent;
    }

    private Map getPidAndComId(String uid, ZKZLReturnDto returnDto) throws Exception {
        Map<String, String> map = new HashMap<>();
        String[] split = uid.split("C");
        if (2 != split.length) {
            returnDto.setReturnCode(202);
            returnDto.setReturnMessage("渠道码不正确");
            throw new Exception(returnDto.getReturnMessage());
        }
        map.put("pId", split[0]);
        map.put("comId", split[1]);
        return map;
    }

    private void getComDockList(Long comId, String dockCode, String serverCode, String channel, ZKZLReturnDto returnDto) throws Exception {
        CompanyDockListDto companyDockListDto = new CompanyDockListDto();
        companyDockListDto.setComId(comId);
        Result comDockListResult = companyClientService.getComDockList(companyDockListDto);
        if (200 != comDockListResult.getCode()) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("获取单位平台对接列表失败");
            throw new Exception(returnDto.getReturnMessage());

        }
        List<CompanyDockListVo> comdockList = JSON.parseArray(JSON.toJSONString(comDockListResult.getData()), CompanyDockListVo.class);
        Optional<CompanyDockListVo> companyDockList = comdockList.stream().filter(companyDockListVo -> dockCode.equals(companyDockListVo.getDockCode()) && serverCode.equals(companyDockListVo.getServerCode()) && channel.equals(companyDockListVo.getComAppid())).findFirst();
        if (!companyDockList.isPresent()) {
            returnDto.setReturnCode(202);
            returnDto.setReturnMessage("渠道码不正确");
            throw new Exception(returnDto.getReturnMessage());
        }
    }

    private void personnelGetPersonInfoAndSetUser(Long comId, Integer pId, ZKZLReturnDto returnDto) throws Exception {
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setOnlyOne(true);
        userInfoVo.setComId(comId);
        userInfoVo.setPId(pId);
        Result getPerson = humanFeignService.PersonnelGetPersonInfo(userInfoVo);
        if (getPerson.getCode() != 200 || getPerson.getData() == null) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("用户信息不存在");
            throw new Exception(returnDto.getReturnMessage());
        }
        EntityPersonnelInfo entityPersonnelInfo = JSON.parseObject(JSON.toJSONString(getPerson.getData()), EntityPersonnelInfo.class);
        returnDto.setUserName(entityPersonnelInfo.getPName());
        returnDto.setUserAccount(entityPersonnelInfo.getPCode());
    }

    private EntityXfAccountInfo getXFAccount(Long comId, Integer pId, ZKZLReturnDto returnDto) throws Exception {
        Result xfAcount = payConfigClientService.GetXFAccount(comId, pId);
        if (xfAcount.getCode() != 200 || null == xfAcount.getData()) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("用户账户不存在");
            returnDto.setUserStatus(3);
            throw new Exception(returnDto.getReturnMessage());
        }
        EntityXfAccountInfo entityXfAccountInfo = JSON.parseObject(JSON.toJSONString(xfAcount.getData()), EntityXfAccountInfo.class);
        if (1 == entityXfAccountInfo.getAccountState()) {
            returnDto.setReturnCode(206);
            returnDto.setReturnMessage("用户账户已冻结");
            returnDto.setUserStatus(2);
            throw new Exception(returnDto.getReturnMessage());
        }
        if (0 == entityXfAccountInfo.getAccountState()) {
            returnDto.setUserStatus(1);
        } else {
            returnDto.setUserStatus(2);
        }
        return entityXfAccountInfo;
    }

    private Map getParam(HttpServletRequest request, ZKZLReturnDto returnDto) throws Exception {
        Map<String, String> map = new HashMap<>();
        try {
            String requestContent = request.getParameter("data");
            logger.info("收到的报文：{}", requestContent);
            map.put("requestContent", requestContent);

            String xsid = (String) request.getHeaders("X-Sid").nextElement();
            logger.info("收到的xsid：{}", xsid);
            map.put("xsid", xsid);

            String xsign = (String) request.getHeaders("X-Sign").nextElement();
            logger.info("收到的xsign：{}", xsign);
            map.put("xsign", xsign);
        } catch (Exception e) {
            e.printStackTrace();
            returnDto.setReturnCode(201);
            returnDto.setReturnMessage("请求参数错误");
            throw new Exception(returnDto.getReturnMessage());
        }
        return map;
    }

}
